#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <sys/select.h>
#include <unordered_map>

#include "Socket.h"
#include "Log.h"
#include "Epoll.h"
#include "Connection.h"

using namespace LogMudule;
using namespace sockedmodule;
using namespace EpollMoudle;

#define NUM sizeof(fd_set) * 8
using std::cout;
using std::endl;
#define MAX 4096
const int gdefaultfd = -1;

using connection_t = std::shared_ptr<Connection>;

class Reactor
{
    const static int event_num = 64;

private:
    bool ISConnectionExits(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

public:
    Reactor()
        : _epoller(std::make_shared<Epoller>()), _isruning(false)
    {
        _epoller->Init();
    }
    void InsertConnection(connection_t conn)
    {
        auto iter = _connections.find(conn->Sockfd());
        if (iter == _connections.end())
        {
            _connections.insert(std::make_pair(conn->Sockfd(), conn));
            _epoller->ADD(conn->Sockfd(), conn->Event());
            conn->SetOwner(this);
            LOG(LogLevel::INFO) << "add connection success" << conn->Sockfd();
        }
    }

    void Dispather(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            int revents = _revs[i].events;
            if ((revents & EPOLLERR) || (revents & EPOLLHUP))
            {
                revents = EPOLLIN | EPOLLOUT;
            }
            if ((revents & EPOLLIN) && ISConnectionExits(sockfd))
            {
                _connections[sockfd]->Recver();
            }
            if ((revents & EPOLLOUT) && ISConnectionExits(sockfd))
            {
                _connections[sockfd]->Sender();
            }
        }
    }
    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {

        if (!ISConnectionExits(sockfd))
        {
            uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
            _connections[sockfd]->SetEvent(events);
            _epoller->Update(sockfd, _connections[sockfd]->Event());
        }
    }
    void DelConnection(int sockfd)
    {

        if (ISConnectionExits(sockfd))
        {
            _epoller->Detele(sockfd);
            _connections[sockfd]->Close();
            _connections.erase(sockfd);
        }
    }
    void Looponce(int timeout)
    {
        int n = _epoller->Wait(_revs, event_num, timeout);
        cout << "Looponce n:" << n << endl;
        Dispather(n);
    }
    void Debugprint()
    {
        std::cout << "eopller 管理的fd" << std::endl;
        for (auto &iter : _connections)
        {
            std::cout << iter.first << " ";
        }
        std::cout << endl;
    }

    void Loop()
    {
        _isruning = true;
        int timeout = -1;
        while (true)
        {
            Looponce(timeout);
            Debugprint();
        }
        _isruning = false;
    }
    ~Reactor()
    {
        }

private:
    std::shared_ptr<Epoller> _epoller;
    std::unordered_map<int, connection_t> _connections;
    bool _isruning;
    struct epoll_event _revs[event_num];
};